using Google.Protobuf;
using Google.Protobuf.Collections;
using Google.Protobuf.Reflection;
using OfficeOpenXml;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Text.RegularExpressions;
using UnityEngine;

namespace ProtoDefine
{
    [System.Serializable]
    public class ProtoMessageInfo
    {
        public string Name;
        public string ExcelFilePath;
        public Dictionary<string, int> AllFiledName = new Dictionary<string, int>();


        /// <summary>
        /// 创建Proto文件
        /// </summary>
        /// <param name="TypeMapping"></param>
        /// <param name="mToolInfo"></param>
        public void GenerateProtoFile(Dictionary<string, string> TypeMapping)
        {
            AllFiledName.Clear();

            PathsInfo mToolInfo = ExcelSheetEditor.mToolInfo;

            FileInfo fileInfo = new FileInfo(ExcelFilePath);
            using (ExcelPackage package = new ExcelPackage(fileInfo))
            {
                ExcelWorksheet worksheet = package.Workbook.Worksheets[mToolInfo.KeyInExcelToParse];

                int columnCount = worksheet.Dimension.Columns;
                int rowCount = worksheet.Dimension.Rows;

                ExcelRange sourData = worksheet.Cells;

                StringBuilder builder = new StringBuilder();
                StreamReader reader = new StreamReader(Path.Combine(mToolInfo.mProtoUtilityPath, "ProtoFileTemplate.syntax"));

                List<string> extraProto = new List<string>();

                while (!reader.EndOfStream)
                {
                    string str = reader.ReadLine().Replace("${MessageName}", Name);

                    str = str.Replace("${ProtoDefine}", mToolInfo.NameSpace);

                    if (str.Contains("#{ForEachField}"))
                    {
                        str = str.Replace("#{ForEachField}", "");
                        List<string> extraType = new List<string>();
                        for (int i = 1; i <= columnCount; i++)
                        {
                            try
                            {
                                string temp = str;
                                string fieldName = Convert.ToString(sourData[mToolInfo.NameLineInExcel, i].Value).Trim();
                                if (!FormatName(ref fieldName)) continue;
                                string Uppertype = Convert.ToString(sourData[mToolInfo.TypeLineInExcel, i].Value).Trim().Replace("repeat_", "");
                                string fieldType = Convert.ToString(sourData[mToolInfo.TypeLineInExcel, i].Value).ToLower().Trim();

                                //注释
                                if (mToolInfo.DescLineInExcel != -1)
                                {
                                    string desc = sourData[mToolInfo.DescLineInExcel, i].Value.ToString();
                                    builder.AppendLine("//" + desc);
                                }

                                //做数组处理
                                string[] typeDefines = fieldType.Split('_');
                                if (!TypeMapping.ContainsKey(Uppertype.ToLower()))
                                {
                                    if (!extraProto.Contains(Uppertype)) extraProto.Add(Uppertype);
                                    fieldType = Uppertype;
                                    if (typeDefines.Length > 1)
                                    {
                                        fieldType = "repeated " + Uppertype;
                                    }
                                }
                                else
                                {
                                    fieldType = TypeMapping[Uppertype.ToLower()];
                                    if (typeDefines.Length > 1)
                                    {
                                        fieldType = "repeated " + TypeMapping[Uppertype.ToLower()];
                                    }
                                }

                                temp = temp.Replace("${FieldType}", fieldType)
                                           .Replace("${FieldName}", fieldName)
                                           .Replace("${Index}", i.ToString());

                                builder.AppendLine(temp);
                            }
                            catch (Exception e)
                            {
                                Debug.LogWarning(string.Format("数据表:{0} 可能具有空行空列。", Name));
                                continue;
                            }
                        }
                    }
                    else
                    {
                        builder.AppendLine(str);
                    }
                }

                //引入其他proto文件
                string importProtoFiles = "";
                foreach (var s in extraProto)
                {
                    importProtoFiles += "import \"" + s + ".proto\";\n";
                }
                builder.Replace("${ExtraProto}", importProtoFiles);

                reader.Dispose();
                reader.Close();
                worksheet.Dispose();

                SaveFile(Name + ".proto", builder.ToString(), mToolInfo.mProtoFilesPath);
            }
        }

        /// <summary>
        /// 创建数据拓展类
        /// </summary>
        public void GenerateExtensionOperation()
        {
            PathsInfo mToolInfo = ExcelSheetEditor.mToolInfo;

            StringBuilder builder = new StringBuilder();
            StreamReader reader = new StreamReader(Path.Combine(mToolInfo.mProtoUtilityPath, "ConfigExtensionTemplate.syntax"));
            while (!reader.EndOfStream)
            {
                string str = reader.ReadLine();
                str = str.Replace("${ClassName}", Name)
                         .Replace("${ProtoDefine}", mToolInfo.NameSpace)
                         .Replace("${DataDirPath}", mToolInfo.mConfigBytesPath);
                builder.AppendLine(str);
            }
            reader.Dispose();
            reader.Close();
            SaveFile(Name + "Extension.cs", builder.ToString(), mToolInfo.mConfigScriptsSavePath);
        }

        /// <summary>
        /// 创建数据赋值类
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="messageInfo"></param>
        /// <param name="mToolInfo"></param>
        public void GenerateAssignTools(Dictionary<string, string> TypeMapping)
        {
            AllFiledName.Clear();

            PathsInfo mToolInfo = ExcelSheetEditor.mToolInfo;

            FileInfo fileInfo = new FileInfo(ExcelFilePath);
            using (ExcelPackage package = new ExcelPackage(fileInfo))
            {
                ExcelWorksheet worksheet = package.Workbook.Worksheets[mToolInfo.KeyInExcelToParse];

                int columnCount = worksheet.Dimension.Columns;
                int rowCount = worksheet.Dimension.Rows;

                ExcelRange sourData = worksheet.Cells;

                StringBuilder builder = new StringBuilder();
                StreamReader reader = new StreamReader(Path.Combine(mToolInfo.mProtoUtilityPath, "ConfigAssignTemplate.syntax"));
                string extraProto = "";

                string normal_base = "";
                string repeat_base = "";
                string normal_message = "";
                string repeat_message = "";

                while (!reader.EndOfStream)
                {
                    string lineText = reader.ReadLine().Replace("${ClassName}", Name);

                    if (lineText.Contains("//#{SingleField}"))
                    {
                        normal_base = lineText.Replace("//#{SingleField}", "");
                        continue;
                    }
                    if (lineText.Contains("//#{RepeatField}"))
                    {
                        repeat_base = lineText.Replace("//#{RepeatField}", ""); ;
                        continue;
                    }
                    if (lineText.Contains("//#{SingleField_Message}"))
                    {
                        normal_message = lineText.Replace("//#{SingleField_Message}", "");
                        continue;
                    }
                    if (lineText.Contains("//#{RepeatField_Message}"))
                    {
                        repeat_message = lineText.Replace("//#{RepeatField_Message}", ""); ;
                        continue;
                    }

                    if (lineText.Contains("#{ForEachField}"))
                    {
                        List<string> extraType = new List<string>();
                        for (int i = 1; i <= columnCount; i++)
                        {
                            try
                            {
                                string fieldName = Convert.ToString(sourData[mToolInfo.NameLineInExcel, i].Value).Trim();
                                if (!FormatName(ref fieldName)) continue;
                                string Uppertype = Convert.ToString(sourData[mToolInfo.TypeLineInExcel, i].Value).Trim().Replace("repeat_", "");
                                string fieldType = Convert.ToString(sourData[mToolInfo.TypeLineInExcel, i].Value).ToLower().Trim();

                                //跳过空行
                                if (string.IsNullOrEmpty(fieldName) || string.IsNullOrEmpty(Uppertype))
                                    continue;

                                string LineString = "";
                                string MethodName = "";

                                //做数组处理
                                string[] typeDefines = fieldType.Split('_');
                                if (!TypeMapping.ContainsKey(Uppertype.ToLower()))
                                {
                                    MethodName = GetConvertMethodName("int32");
                                    LineString = normal_message.Replace("${TClassName}", Uppertype);
                                    if (typeDefines.Length > 1)
                                    {
                                        LineString = repeat_message.Replace("${TClassName}", Uppertype);
                                    }
                                }
                                else
                                {
                                    LineString = normal_base;
                                    fieldType = TypeMapping[Uppertype.ToLower()];
                                    MethodName = GetConvertMethodName(fieldType);
                                    if (typeDefines.Length > 1)
                                    {
                                        LineString = repeat_base;
                                    }
                                }


                                LineString = LineString.Replace("${FieldName}", fieldName)
                                     .Replace("${MethodName}", MethodName)
                                     .Replace("${DataIndex}", i.ToString());

                                builder.AppendLine(LineString);
                            }
                            catch (Exception e)
                            {
                                Debug.LogWarning(string.Format("数据表:{0} 可能具有空行空列。", Name));
                                continue;
                            }
                        }
                    }
                    else
                    {
                        builder.AppendLine(lineText);
                    }
                }

                builder.Replace("${ExtraProto}", extraProto);

                reader.Dispose();
                reader.Close();
                worksheet.Dispose();

                string fileDirPath = Path.Combine(mToolInfo.mProtoUtilityPath, mToolInfo.AssignDataToolsPath);
                SaveFile(Name + "Tools.cs", builder.ToString(), fileDirPath);
            }
        }

        //----工具类-----------------------------------------------------------------------------------------

        /// <summary>
        /// 规范命名
        /// </summary>
        /// <param name="filedName"></param>
        /// <returns></returns>
        private bool FormatName(ref string filedName)
        {
            //第一个字母大写
            filedName = filedName.ToArray()[0].ToString().ToUpper() + filedName.Substring(1);

            //_下划线后第一个字母大写
            Regex r = new Regex(@"_\w");//构造表达式
            MatchCollection matchCollection = r.Matches(filedName);

            for (int i = 0; i < matchCollection.Count; i++)
            {
                filedName = filedName.Replace(matchCollection[i].Value, matchCollection[i].Value.ToCharArray()[1].ToString().ToUpper());
            }

            if (filedName.ToUpper() == "ID") filedName = "ID";

            if (AllFiledName.ContainsKey(filedName))
            {
                Debug.LogError(string.Format("数据表：{0} 中字段名：{1} 重复。", Name, filedName));
                return false;
            }
            else
            {
                AllFiledName.Add(filedName, 1);
            }

            return true;
        }

        /// <summary>
        /// 创建文件
        /// </summary>
        /// <param name="fileName">文件全名</param>
        /// <param name="content">文件内容</param>
        /// <param name="fileSaveDirPath">存储文件的文件夹</param>
        private static void SaveFile(string fileName, string content, string fileSaveDirPath)
        {
            if (!Directory.Exists(fileSaveDirPath)) Directory.CreateDirectory(fileSaveDirPath);
            string filePath = Path.Combine(fileSaveDirPath, fileName);
            if (File.Exists(filePath)) File.Delete(filePath);
            File.AppendAllText(filePath, content);
        }

        public string GetConvertMethodName(string field)
        {
            switch (field)
            {
                case "double": return "Convert.ToDouble";
                case "float": return "Convert.ToSingle";
                case "int64": return "Convert.ToInt64";
                //case "" FieldType.UInt64: return "Convert.ToUInt64";
                case "int32": return "Convert.ToInt32";
                case "bool": return "Convert.ToBoolean";
                case "string": return "Convert.ToString";
                //case "message": target = return "Convert.ToDouble";Convert
                case "bytes": return "Convert.ToByte";
                //case "" FieldType.UInt32: return "Convert.ToUInt32";
                default: return "";
            }

            // case FieldType.Bool:
            //    fieldType.Accessor.SetValue(target, default(Boolean));
            //if (value != null)
            //{
            //    switch (value.ToString().ToLower())
            //    {
            //        case "true": fieldType.Accessor.SetValue(target, true); break;
            //        case "false": fieldType.Accessor.SetValue(target, false); break;
            //        case "flase": fieldType.Accessor.SetValue(target, false); break;
            //    }
            //}
            //break;
        }
    }
}


